package com.the_last.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.the_last.constant.RedisKeyConstant;
import com.the_last.mapper.SysRoleMapper;
import com.the_last.mapper.SysUserRoleMapper;
import com.the_last.mapper.UserMapper;
import com.the_last.pojo.dto.IncrementalUserRoleDTO;
import com.the_last.pojo.po.SysRole;
import com.the_last.pojo.po.SysUserRole;
import com.the_last.pojo.po.User;
import com.the_last.service.ISysUserRoleService;
import com.the_last.utils.RedisUtil;
import com.the_last.utils.Result;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserRoleServiceImpl extends ServiceImpl<SysUserRoleMapper, SysUserRole>
        implements ISysUserRoleService {
    
    private final UserMapper userMapper;
    private final SysRoleMapper roleMapper;
    private final RedisUtil redisUtil;
    private final RedissonClient redissonClient;
    private final ExecutorService executorService;
    
    @Override
    @Transactional
    public Result<Void> incrementalAssignUserRoles(IncrementalUserRoleDTO incrementalDTO) {
        if (incrementalDTO == null || incrementalDTO.getUserId() == null) {
            return Result.fail("用户ID不能为空");
        }
        
        if (!incrementalDTO.hasValidOperation()) {
            return Result.fail("至少需要指定一个操作：添加角色或删除角色");
        }
        
        Long userId = incrementalDTO.getUserId();
        List<Long> addRoleIds = incrementalDTO.getAddRoleIds();
        List<Long> removeRoleIds = incrementalDTO.getRemoveRoleIds();
        
        try {
            // 1. 验证用户存在
            User user = userMapper.selectById(userId);
            if (user == null || user.getDeleted().equals(1)) {
                return Result.fail("用户不存在");
            }
            
            // 2. 处理角色删除操作
            if (removeRoleIds != null && !removeRoleIds.isEmpty()) {
                Result<Void> removeResult = removeRolesFromUser(userId, removeRoleIds);
                if (removeResult.getCode() != 200) {
                    return Result.fail("删除角色失败: " + removeResult.getMsg());
                }
            }
            
            // 3. 处理角色添加操作
            if (addRoleIds != null && !addRoleIds.isEmpty()) {
                // 验证角色有效性（使用缓存）
                Set<Long> validRoleIds = getValidRoleIds();
                List<Long> filteredAddRoleIds = addRoleIds.stream()
                        .distinct() // 去重
                        .filter(validRoleIds::contains) // 只保留有效的角色ID
                        .toList();
                
                if (filteredAddRoleIds.size() != addRoleIds.size()) {
                    return Result.fail("存在无效的角色");
                }
                
                // 创建新的用户角色关联记录
                List<SysUserRole> userRoles = filteredAddRoleIds.stream()
                        .map(roleId -> {
                            SysUserRole userRole = new SysUserRole();
                            userRole.setUserId(userId);
                            userRole.setRoleId(roleId);
                            userRole.setCreatedTime(LocalDateTime.now());
                            userRole.setDeleted(0);
                            return userRole;
                        }).toList();
                
                saveBatch(userRoles);
                log.info("用户[{}]新增角色{}个", userId, userRoles.size());
            }
            
            // 4. 更新用户权限版本（如果有任何变更）
            changeUserPermVersion(user, userId);
            
            return Result.success();
        } catch (Exception e) {
            log.error("增量分配用户角色失败，userId: {}", userId, e);
            return Result.fail("增量分配用户角色失败");
        }
    }
    
    @Override
    @Transactional
    public Result<Void> removeRolesFromUser(Long userId, List<Long> roleIds) {
        if (userId == null || CollectionUtils.isEmpty(roleIds)) {
            return Result.fail("用户ID和角色ID列表不能为空");
        }
        
        try {
            QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId)
                    .in("role_id", roleIds)
                    .eq("deleted", 0);
            
            List<SysUserRole> userRoles = list(queryWrapper);
            if (!CollectionUtils.isEmpty(userRoles)) {
                // 批量软删除
                List<Long> userRoleIds = userRoles.stream()
                        .map(SysUserRole::getId)
                        .collect(Collectors.toList());
                baseMapper.batchSoftDelete(userRoleIds);
            }
            
            changeUserPermVersion(null, userId);
            return Result.success();
        } catch (Exception e) {
            log.error("移除用户角色失败，userId: {}", userId, e);
            return Result.fail("移除用户角色失败");
        }
    }
    
    @Override
    public Result<List<Long>> getRoleIdsByUserId(Long userId) {
        if (userId == null) {
            return Result.fail("用户ID不能为空");
        }
        
        try {
            
            QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("deleted", 0);
            
            List<SysUserRole> userRoles = list(queryWrapper);
            List<Long> roleIds = userRoles.stream()
                    .map(SysUserRole::getRoleId)
                    .collect(Collectors.toList());
            
            return Result.success(roleIds);
        } catch (Exception e) {
            log.error("查询用户角色ID失败，userId: {}", userId, e);
            return Result.fail("查询用户角色失败");
        }
    }
    
    @Override
    public Result<List<Long>> getUserIdsByRoleId(Long roleId) {
        if (roleId == null) {
            return Result.fail("角色ID不能为空");
        }
        
        try {
            
            QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("role_id", roleId).eq("deleted", 0);
            
            List<SysUserRole> userRoles = list(queryWrapper);
            List<Long> userIds = userRoles.stream()
                    .map(SysUserRole::getUserId)
                    .collect(Collectors.toList());
            
            return Result.success(userIds);
        } catch (Exception e) {
            log.error("查询角色用户ID失败，roleId: {}", roleId, e);
            return Result.fail("查询角色用户失败");
        }
    }
    
    @Override
    @Transactional
    public Result<Void> batchAssignRoleToUsers(List<Long> userIds, Long roleId) {
        if (CollectionUtils.isEmpty(userIds) || roleId == null) {
            return Result.fail("用户ID列表和角色ID不能为空");
        }
        
        try {
            // 验证角色有效性（使用缓存）
            Set<Long> validRoleIds = getValidRoleIds();
            if (!validRoleIds.contains(roleId)) {
                return Result.fail("角色不存在或已禁用");
            }
            
            List<User> users = userMapper.selectBatchIds(userIds);
            List<Long> validUserIds = users.stream()
                    .filter(user -> !user.getDeleted().equals(1) && user.getStatus().equals(1))
                    .map(User::getId)
                    .toList();
            
            if (validUserIds.size() != userIds.size()) {
                return Result.fail("存在无效的用户");
            }
            
            // 🚀 优化：一次性批量查询现有用户角色关联，避免N+1查询问题
            QueryWrapper<SysUserRole> batchExistQuery = new QueryWrapper<>();
            batchExistQuery.in("user_id", validUserIds)
                    .eq("role_id", roleId)
                    .eq("deleted", 0);
            List<SysUserRole> existingUserRoles = list(batchExistQuery);
            
            // 在内存中构建已存在关联的用户ID集合
            Set<Long> existingUserIds = existingUserRoles.stream()
                    .map(SysUserRole::getUserId)
                    .collect(Collectors.toSet());
            
            // 过滤出需要新增关联的用户ID
            List<SysUserRole> userRoles = validUserIds.stream()
                    .filter(userId -> !existingUserIds.contains(userId))
                    .map(userId -> {
                        SysUserRole userRole = new SysUserRole();
                        userRole.setUserId(userId);
                        userRole.setRoleId(roleId);
                        userRole.setCreatedTime(LocalDateTime.now());
                        userRole.setDeleted(0);
                        return userRole;
                    })
                    .collect(Collectors.toList());
            
            
            if (!CollectionUtils.isEmpty(userRoles)) {
                saveBatch(userRoles);
                // 更新相关用户的权限版本号
                List<Long> affectedUserIds = userRoles.stream()
                        .map(SysUserRole::getUserId)
                        .distinct()
                        .collect(Collectors.toList());
                userMapper.batchUpdatePermVersion(affectedUserIds);
            }
            return Result.success();
        } catch (Exception e) {
            log.error("批量分配角色失败，roleId: {}", roleId, e);
            return Result.fail("批量分配角色失败");
        }
    }
    
    @Override
    @Transactional
    public Result<Void> clearUserRoles(Long userId) {
        if (userId == null) {
            return Result.fail("用户ID不能为空");
        }
        
        try {
            QueryWrapper<SysUserRole> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_id", userId).eq("deleted", 0);
            
            List<SysUserRole> userRoles = list(queryWrapper);
            if (!CollectionUtils.isEmpty(userRoles)) {
                // 批量软删除
                List<Long> userRoleIds = userRoles.stream()
                        .map(SysUserRole::getId)
                        .collect(Collectors.toList());
                baseMapper.batchSoftDelete(userRoleIds);
            }
            
            changeUserPermVersion(null, userId);
            return Result.success();
        } catch (Exception e) {
            log.error("清除用户角色失败，userId: {}", userId, e);
            return Result.fail("清除用户角色失败");
        }
    }
    
    @Override
    public Result<Boolean> hasRole(Long userId, String roleCode) {
        if (userId == null || roleCode == null) {
            return Result.fail("用户ID和角色编码不能为空");
        }
        
        try {
            String cacheKey = "user:has:role:" + userId + ":" + roleCode;
            Boolean cachedResult = redisUtil.getObject(cacheKey, Boolean.class);
            if (cachedResult != null) {
                return Result.success(cachedResult);
            }
            
            QueryWrapper<SysUserRole> userRoleQuery = new QueryWrapper<>();
            userRoleQuery.eq("user_id", userId).eq("deleted", 0);
            
            List<SysUserRole> userRoles = list(userRoleQuery);
            if (CollectionUtils.isEmpty(userRoles)) {
                redisUtil.set(cacheKey, false, (Integer) 300);
                return Result.success(false);
            }
            
            List<Long> roleIds = userRoles.stream()
                    .map(SysUserRole::getRoleId)
                    .collect(Collectors.toList());
            
            QueryWrapper<SysRole> roleQuery = new QueryWrapper<>();
            roleQuery.in("id", roleIds)
                    .eq("role_code", roleCode)
                    .eq("status", 1)
                    .eq("deleted", 0);
            
            boolean hasRole = roleMapper.selectCount(roleQuery) > 0;
            redisUtil.set(cacheKey, hasRole, (Integer) 300); // 5分钟缓存
            return Result.success(hasRole);
        } catch (Exception e) {
            log.error("检查用户角色失败，userId: {}, roleCode: {}", userId, roleCode, e);
            return Result.fail("检查用户角色失败");
        }
    }
    
    /**
     * 清除特定用户角色缓存
     */
    private void changeUserPermVersion(User user, Long userId) {
        if (user == null) {
            user = userMapper.selectOne(new QueryWrapper<User>().eq("id", userId));
        }
        Integer permVersion = user.getPermVersion();
        permVersion++;
        user.setPermVersion(permVersion);
        userMapper.updateById(user);
        redisUtil.set(RedisKeyConstant.USER_PERM_VERSION_KEY + userId, permVersion);
    }
    
    /**
     * 获取有效的角色ID列表（带缓存）
     *
     * @return 有效角色ID集合
     */
    private Set<Long> getValidRoleIds() {
        // 先从缓存获取
        Set<Long> cachedRoleIds = redisUtil.getSet(RedisKeyConstant.VALID_ROLE_IDS_KEY, Long.class);
        if (!CollectionUtils.isEmpty(cachedRoleIds)) {
            return cachedRoleIds;
        }
        return loadAndCacheValidRoleIds();
    }
    
    /**
     * 从数据库加载有效角色ID并缓存
     *
     * @return 有效角色ID集合
     */
    private Set<Long> loadAndCacheValidRoleIds() {
        RLock lock = redissonClient.getLock(RedisKeyConstant.VALID_ROLE_IDS_LOCK_KEY);
        try {
            // 尝试获取锁，最多等待3秒，锁定10秒后自动释放
            if (lock.tryLock(3, 10, TimeUnit.SECONDS)) {
                try {
                    Set<Long> cachedRoleIds = redisUtil.getSet(RedisKeyConstant.VALID_ROLE_IDS_KEY, Long.class);
                    if (!CollectionUtils.isEmpty(cachedRoleIds)) {
                        return cachedRoleIds;
                    }
                    
                    // 从数据库查询有效角色ID
                    QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("status", 1)
                            .eq("deleted", 0)
                            .select("id");
                    
                    List<SysRole> validRoles = roleMapper.selectList(queryWrapper);
                    Set<Long> validRoleIds = validRoles.stream()
                            .map(SysRole::getId)
                            .collect(Collectors.toSet());
                    
                    // 缓存30分钟
                    redisUtil.addToSet(RedisKeyConstant.VALID_ROLE_IDS_KEY, validRoleIds);
                    
                    log.info("已缓存有效角色ID列表，共{}个角色", validRoleIds.size());
                    return validRoleIds;
                } finally {
                    lock.unlock();
                }
            } else {
                // 获取锁失败，直接查询数据库
                log.warn("获取角色缓存锁失败，直接查询数据库");
                return queryValidRoleIdsFromDb();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("获取角色缓存锁时被中断", e);
            return queryValidRoleIdsFromDb();
        } catch (Exception e) {
            log.error("加载角色缓存时发生异常", e);
            return queryValidRoleIdsFromDb();
        }
    }
    
    /**
     * 直接从数据库查询有效角色ID（不使用缓存）
     *
     * @return 有效角色ID集合
     */
    private Set<Long> queryValidRoleIdsFromDb() {
        QueryWrapper<SysRole> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", 1)
                .eq("deleted", 0)
                .select("id");
        
        List<SysRole> validRoles = roleMapper.selectList(queryWrapper);
        return validRoles.stream()
                .map(SysRole::getId)
                .collect(Collectors.toSet());
    }
    
    /**
     * 清除有效角色ID缓存
     * 用于角色状态变更时
     */
    public void clearValidRoleIdsCache() {
        redisUtil.delete(RedisKeyConstant.VALID_ROLE_IDS_KEY);
        log.info("已清除有效角色ID缓存");
    }
}